package com.iagent.register;

import com.iagent.logging.LogFactory;
import com.iagent.logging.Logger;
import com.iagent.util.Assert;

import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

/**
 * An abstract registry that writes common methods
 *
 * @auther liujieyu
 * @date 2022/12/17
 * @description
 * @since 2.0.0
 */
public abstract class AbstractBeanRegister<T> implements BeanRegister<T> {

    private static final Logger logger = LogFactory.getLogger(AbstractBeanRegister.class);

    /**
     * Registry core container
     */
    private ConcurrentHashMap<String, Object> coreContainer = null;

    public AbstractBeanRegister() {
        super();
        coreContainer = new ConcurrentHashMap<>(16);
    }

    public AbstractBeanRegister(int initialCapacity) {
        super();
        coreContainer = new ConcurrentHashMap<>(initialCapacity);
    }

    /**
     * Register beans into the container
     *
     * @param beanName key
     * @param target value
     * @return
     */
    public boolean registerBean(String beanName, T target) {
        Assert.notNull(beanName, "Register Container bean name is Null!");
        Assert.notNull(target, "Register Container target is Null!");
        try {
            coreContainer.put(beanName, target);
            return true;
        } catch (Throwable t) {
            logger.error("Register Container is Error, Message:" + t.getMessage());
            return false;
        }
    }

    /**
     * Gets objects in a container by name
     *
     * @param beanName
     * @return
     */
    public T getBeanObject(String beanName) {
        Assert.notNull(beanName, "The BeanName of Get Object By Container is Null!");
        return (T) coreContainer.get(beanName);
    }

    /**
     * Determine whether the name contains the corresponding data in the container
     *
     * @param beanName
     * @return
     */
    public boolean containBeanName(String beanName) {
        return coreContainer.containsKey(beanName);
    }

    /**
     * Removes the name specified in the container
     *
     * @param beanName
     * @return
     */
    public boolean removeBean(String beanName) {
        Assert.notNull(beanName, "Delete Container bean name is Null!");
        try {
            coreContainer.remove(beanName);
            return true;
        } catch (Throwable t) {
            logger.error("Delete from Container By BeanName is Error, BeanName:" + beanName);
            return false;
        }
    }

    /**
     * Removes the specified name and type from the container
     *
     * @param beanName
     * @return
     */
    public void removeBeanAndClass(String beanName, Class<?> clazz) {
        Object o = coreContainer.get(beanName);
        if (o.getClass().isAssignableFrom(clazz)) {
            removeBean(beanName);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("remove bean name [" + beanName + "] fail, the class [" + o.getClass() + "] is not extends or implement by" + clazz);
            }
        }
    }

    @Override
    public String[] getAllBeanNames() {
        String[] keys = new String[coreContainer.size()];
        Enumeration<String> enumeration = coreContainer.keys();
        int index = 0;
        while (enumeration.hasMoreElements()) {
            keys[index] = enumeration.nextElement();
            index ++;
        }
        return keys;
    }

    @Override
    public int size() {
        return coreContainer.size();
    }

    @Override
    public void removeAll() {
        coreContainer.clear();
    }
}
